%{
#include <stdio.h>
#define YYDEBUG 1
%}
%union{
    char                identifier;
    PackageName         package_name;
    ParameterList       parameter_list;
    ArgumentList        argument_list;
    Expression          expression;
    ExpressionList      expression_list;
    Statement           statement;
    StatementList       statement_list;
    Block               block;
    Elsif               elsif;
    CaseList            case_list;
    AssignmentOperator  assignment_operator;
    FunctionDefinition  function_definition;
    IdentifierList      identifier_list;
}
%token <expression>     INT_LITERAL
%token <expression>     DOUBLE_LITERAL
%token <expression>     COMPLEX_LITERAL
%token <expression>     STRING_LITERAL
%token <expression>     REGEXP_LITERAL
%token <identifier>     IDENTIFIER
%token <identifier>     GLOBAL
%token FUNCTION IF ELSE ELSIF WHILE FOR SWITCH CASE DEFAULT TRY CATCH FINALLY
        RETURN_T BREAK CONTINUE IMPORT CONST
        NULL_T TRUE_T FALSE_T
        ASSIGN_T EQ NE GT GE LT LE ADD SUB MUL DIV MOD EXCLAMATION MOD_ASSIGN_T BIT_AND_ASSIGN_T BIT_AND ADD_ASSIGN_T SUB_ASSIGN_T MUL_ASSIGN_T DIV_ASSIGN_T BIT_XOR_ASSIGN_T BIT_OR_ASSIGN_T
        DOT_MUL DOT_DIV BIT_XOR BIT_OR BIT_NOT
        LOGICAL_AND LOGICAL_OR INCREMENT DECREMENT
        SEMICOLON COMMA COLON DOT AS
        LP RP LC RC LB RB
%type   <package_name> package_name require_list require_declaration
%type   <parameter_list> parameter_list
%type   <argument_list> argument_list
%type   <expression> expression expression_opt
        assignment_expression logical_expression 
        equality_expression relational_expression
        additive_expression multiplicative_expression
        unary_expression postfix_expression primary_expression array_literal
%type   <expression_list> expression_list
%type   <statement> statement if_statement while_statement for_statement
        return_statement break_statement continue_statement try_statement
        const_statement  switch_statement block_statement
%type   <statement_list> statement_list
%type   <block> block
%type   <elsif> elsif elsif_list
%type   <case_list> case_list one_case
%type   <assignment_operator> assignment_operator
%type   <identifier_list> identifier_list identifier1
%%
translation_unit
        : initial_declaration definition_or_statement
        | translation_unit definition_or_statement
        ;
initial_declaration
        :  /* empty */
        {}
        | require_list
        {}
        ;
require_list
        : require_declaration
        | require_list require_declaration
        {}
        ;
require_declaration
        : IMPORT package_name SEMICOLON
        {}
        | IMPORT package_name AS IDENTIFIER SEMICOLON
         {}
        ;
package_name
        : IDENTIFIER
        {}
        | package_name DOT IDENTIFIER
        {}
        ;
definition_or_statement
        : function_definition
        | statement
        {}
        ;
function_definition
        : FUNCTION IDENTIFIER LP parameter_list RP block
        {}
        | FUNCTION IDENTIFIER LP RP block
        {}
        ;
parameter_list
        : IDENTIFIER
        {}
        | parameter_list COMMA IDENTIFIER
        {}
        ;
argument_list
        : assignment_expression
        {}
        | argument_list COMMA assignment_expression
        {}
        ;
statement_list
        : statement
        {}
        | statement_list statement
        {}
        ;
expression
        :assignment_expression
        | expression COMMA assignment_expression
        {}
        ;
assignment_expression
        : logical_expression
        | postfix_expression assignment_operator assignment_expression
        {}
        ;
assignment_operator
        : ASSIGN_T
        {}
        | ADD_ASSIGN_T
        {}
        | SUB_ASSIGN_T
        {}
        | MUL_ASSIGN_T
        {}
        | DIV_ASSIGN_T
        {}
        | MOD_ASSIGN_T
        {}
        | BIT_XOR_ASSIGN_T
        {}
        | BIT_AND_ASSIGN_T
        {}
        | BIT_OR_ASSIGN_T
        {}
        ;
logical_expression
        : equality_expression
        | logical_expression LOGICAL_AND equality_expression
        {}
        | logical_expression LOGICAL_OR equality_expression
        {}
        | logical_expression BIT_AND equality_expression
        {}
        | logical_expression BIT_OR equality_expression
        {}
        | logical_expression BIT_XOR equality_expression
        {}
        ;
equality_expression
        : relational_expression
        | equality_expression EQ relational_expression
        {}
        | equality_expression NE relational_expression
        {}
        ;
relational_expression
        : additive_expression
        | relational_expression GT additive_expression
        {}
        | relational_expression GE additive_expression
        {}
        | relational_expression LT additive_expression
        {}
        | relational_expression LE additive_expression
        {}
        ;
additive_expression
        : multiplicative_expression
        | additive_expression ADD multiplicative_expression
        {}
        | additive_expression SUB multiplicative_expression
        {}
        ;
multiplicative_expression
        : unary_expression
        | multiplicative_expression MUL unary_expression
        {}
        | multiplicative_expression DIV unary_expression
        {}
        | multiplicative_expression MOD unary_expression
        {}
        | multiplicative_expression DOT_MUL unary_expression
        {}
        | multiplicative_expression DOT_DIV unary_expression
        {}
        ;
unary_expression
        : postfix_expression
        | SUB unary_expression
        {}
        | EXCLAMATION unary_expression
        {}
        | BIT_NOT unary_expression
        {}
        ;
postfix_expression
        : primary_expression
        | postfix_expression INCREMENT
        {}
        | postfix_expression DECREMENT
        {}
        | postfix_expression LB expression RB
        {}
        | postfix_expression LP argument_list RP
        {}
        | postfix_expression LP RP
        {}
        ;
primary_expression
        : LP expression RP
        {}
        | IDENTIFIER
        {}
        | IDENTIFIER DOT IDENTIFIER
        {}
        | INT_LITERAL
        | DOUBLE_LITERAL
        | COMPLEX_LITERAL
        | STRING_LITERAL
        | REGEXP_LITERAL
        | TRUE_T
        {}
        | FALSE_T
        {}
        | NULL_T
        {}
        | array_literal
        | GLOBAL
        {}
        ;
array_literal
        : LB RB
        {}
        | LB expression_list RB
        {}
        ;
expression_list
        : expression_list1
        {}
        | expression_list SEMICOLON expression_list1
        {}
        ;
expression_list1
        : assignment_expression
        {}
        | expression_list1 COMMA assignment_expression
        {}
        ;
statement
        : expression SEMICOLON
        {}
        | if_statement
        | while_statement
        | switch_statement
        | for_statement
        | return_statement
        | break_statement
        | continue_statement
        | try_statement
        | const_statement
        | block_statement
        ;
const_statement
        : CONST identifier_list SEMICOLON
        {}
        ;
identifier_list
        : identifier1
        | identifier_list COMMA identifier1
        {}
        ;
identifier1
        : IDENTIFIER ASSIGN_T identifier2
        {}
        ;
identifier2
        : INT_LITERAL
         | DOUBLE_LITERAL
         | COMPLEX_LITERAL
         | STRING_LITERAL
         | TRUE_T
         {}
         | FALSE_T
         {}
         | NULL_T
         {}
         | array_literal
 if_statement
         : IF LP expression RP block
         {}
         | IF LP expression RP block ELSE block
         {}
         | IF LP expression RP block elsif_list
         {}
         | IF LP expression RP block elsif_list ELSE block
         {}
         ;
 elsif_list
         : elsif
         | elsif_list elsif
         {}
         ;
 elsif
         : ELSIF LP expression RP block
         {}
         ;
 while_statement
         : WHILE LP expression RP block
         {}
         ;
 switch_statement
         : SWITCH LP expression RP LC case_list default_opt RC
         {}
         ;
 case_list
         : one_case
         | case_list one_case
         {}
         ;
 one_case
         : CASE expression_list1 COLON block
         {}
         ;
 default_opt
         : /* empty */
         {}
         | DEFAULT COLON block
         {}
         ;
 for_statement
         : FOR LP expression_opt SEMICOLON expression_opt SEMICOLON
           expression_opt RP block
         {}
         ;
 expression_opt
         : /* empty */
         {
             $$ = NULL;
         }
         | expression
         ;
 return_statement
         : RETURN_T expression_opt SEMICOLON
         {}
         ;
 break_statement
         : BREAK SEMICOLON
         {}
         ;
 continue_statement
         : CONTINUE  SEMICOLON
         {}
         ;
 try_statement
         : TRY block CATCH LP IDENTIFIER RP block FINALLY block
         {}
         | TRY block CATCH LP IDENTIFIER RP block
         {}
 block_statement
         : block
         {
         }
         ;
 block
         : LC statement_list RC
         {}
         | LC RC
         {}
         ;
%%
